﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using Service.ServiceInstances;
using Contract.ServiceContracts;

namespace SelfHost.ServiceConsole
{
    class Program
    {
        static void Main(string[] args) 
        {
            //Uri baseAddress = new Uri("http://localhost:8000/");
            //Uri wsHttpAddress = new Uri("http://localhost:1000/MathClass");
            //Uri bsHttpAddress = new Uri("http://localhost:2000/MathClass");
            //Uri tcpAddress = new Uri("net.tcp://localhost:7000/MathClass");


            //BasicHttpBinding bsHttpBind = new BasicHttpBinding();
            //WSHttpBinding wsHttpBind = new WSHttpBinding();
            
            //NetTcpBinding tcpBind = new NetTcpBinding();
            //tcpBind.TransactionFlow = true;

            //NetNamedPipeBinding ipcBind = new NetNamedPipeBinding();
            //WS2007FederationHttpBinding federa2007Bind = new WS2007FederationHttpBinding();
            //WS2007HttpBinding http2007Bind = new WS2007HttpBinding();
            //WSDualHttpBinding dualHttpBind = new WSDualHttpBinding();
            //WSFederationHttpBinding federaBind = new WSFederationHttpBinding();
            //NetPeerTcpBinding p2pBind = new NetPeerTcpBinding();
            //NetMsmqBinding msmqBind = new NetMsmqBinding();
            
            
            //read base address from app.config 
            //ServiceHost host = new ServiceHost(typeof(MathClass));
            

            //ServiceHost host2 = new ServiceHost(typeof(MathCustomClass));

            //use code add base address

            //ServiceHost host = new ServiceHost(typeof(MathClass),baseAddress);

            //default read end points from app.config
            
            //use code add endpoint
            //host.AddServiceEndpoint(typeof(IMathServices), wsHttpBind, "Test");
            //host.AddServiceEndpoint(typeof(IMathServices), p2pBind, "Test");
            //host.AddServiceEndpoint(typeof(IMathServices), tcpBind, "Test");


            //default read behaviors from app.config

            //use code add behaviors
            //ServiceMetadataBehavior metadataBehavior;
            //metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
            //if (metadataBehavior == null) 
            //{
            //    metadataBehavior = new ServiceMetadataBehavior();
            //    metadataBehavior.HttpGetEnabled = true;
            //    host.Description.Behaviors.Add(metadataBehavior);
            //}

            

            //try
            //{
            //    host.Open();

            //    ShowHostInfo(host);

            //    Console.ReadLine();
            //}
            //catch (CommunicationException exp)
            //{
            //    throw exp;
            //}
            //finally 
            //{
            //    host.Close();
               
            //}

            ServiceHostCollection list = new ServiceHostCollection();
            ServiceHost math = new ServiceHost(typeof(MathClass),new Uri("http://localhost:8000"));
            math.AddServiceEndpoint(typeof(IMathServices),new WSHttpBinding(),"Test");

            ServiceMetadataBehavior metadataBehavior;
            metadataBehavior = math.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (metadataBehavior == null) 
            {
                metadataBehavior = new ServiceMetadataBehavior();
                metadataBehavior.HttpGetEnabled = true;
                math.Description.Behaviors.Add(metadataBehavior);
            }

            ServiceHost custom = new ServiceHost(typeof(MathCustomClass),new Uri("http://localhost:7000"));
            custom.AddServiceEndpoint(typeof(IMathServices),new WSHttpBinding(),"Test");
            
            //ServiceMetadataBehavior metadataBehavior;
            metadataBehavior = custom.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (metadataBehavior == null) 
            {
                metadataBehavior = new ServiceMetadataBehavior();
                metadataBehavior.HttpGetEnabled = true;
                custom.Description.Behaviors.Add(metadataBehavior);
            }
            
            list.AddHost(math);
            list.AddHost(custom);

            try
            {
                foreach(ServiceHost h in list)
                {
                    h.Open();

                    ShowHostInfo(h);
                }
                
                Console.ReadLine();
            }
            catch (CommunicationException exp)
            {
                throw exp;
            }
            finally 
            {
                foreach (ServiceHost h in list)
                {
                    h.Close();
                }
               
            }
        }

        private static void ShowHostInfo(ServiceHost host)
        {
            Console.WriteLine("Base Addresses");
            foreach (var uri in host.BaseAddresses)
            {
                Console.WriteLine(string.Format("\r\n Address = {0} \r\n", uri.AbsoluteUri));
            }
            Console.WriteLine();

            ShowChannelDispatcherInfo(host);

            Console.WriteLine("Endpoints");
            foreach (var point in host.Description.Endpoints)
            {
                Console.WriteLine(string.Format("\r\n Name = {0}, \r\n Address = {1}, \r\n Contract = {2}, \r\n Binding = {3} \r\n"
                    , point.Name
                    , point.Address.Uri
                    , point.Contract.Name
                    , point.Binding.Name
                    ));
            }
            Console.WriteLine();

            

            Console.WriteLine("All Behavior");
            foreach (var behavior in host.Description.Behaviors)
            {
                Console.WriteLine(behavior);
            }
            Console.WriteLine();
        }

        private static void ShowChannelDispatcherInfo(ServiceHost host) 
        {
            Console.WriteLine("Channel Dispatcher Info");
            Console.WriteLine();
            foreach (var dispatcher in host.ChannelDispatchers)
            {

                Console.WriteLine("Dispatcher Info");
                Console.WriteLine(string.Format("\r\n Description = {0}, State = {1}", dispatcher.Host.Description.Name, dispatcher.State));
                Console.WriteLine();
                Console.WriteLine("Listener Info");
                Console.WriteLine(string.Format("\r\n Address = {0}, \r\n State = {1} \r\n", dispatcher.Listener.Uri, dispatcher.Listener.State));
            }
            Console.WriteLine();
        }
    }

    public class ServiceHostCollection : IEnumerable<ServiceHost>
    {
        public List<ServiceHost> HostList 
        { get; private set; }

        public ServiceHostCollection() 
        {
            HostList = new List<ServiceHost>();
        }

        public ServiceHost this[int index]
        {
            get 
            {
                if (HostList != null && HostList.Count > 0)
                {
                    return HostList[index];
                }
                else 
                {
                    return null;
                }
            }
            
        } 

        public void AddHost(ServiceHost host) 
        {
           
            HostList.Add(host);
        }

        public void RemoveHost(ServiceHost host) 
        {
            
            HostList.Remove(host);
            
        }


        public IEnumerator<ServiceHost> GetEnumerator()
        {
            return HostList.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return HostList.GetEnumerator();
        }
    }
}
